package org.jflame.captcha.creator;

import org.jflame.captcha.Captcha;
import org.jflame.captcha.CaptchaUtils;
import org.jflame.captcha.validator.SingleVerifiable;
import org.jflame.commons.file.ImageHelper;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.Serializable;

import org.apache.commons.lang3.RandomUtils;

/**
 * 传统图片验证码,生成文字图片,文字可以是随机字符或数学公式等.
 * <p>
 * 数学公式验证码: {@code
 *  new ImageCaptchaCreator(new MathCaptchaCreator());
 * } </pre>
 * 
 * @author charles.zhang
 */
public class SimpleImageCaptchaCreator<V extends Serializable>
        implements CaptchaCreator<SingleVerifiable<V>,SimpleImage> {

    private AbstractTextCaptchaCreator<V> codeCreator;
    protected Font defaultFont = null;// 字体
    protected int width = 90;// 图片默认宽度
    protected int height = 40;// 图片默认高度
    protected boolean isDrawBorder = true;// 图片是否绘制边框

    /**
     * 构造函数
     * 
     * @param _codeCreator 文本验证码生成器
     */
    public SimpleImageCaptchaCreator(AbstractTextCaptchaCreator<V> _codeCreator) {
        codeCreator = _codeCreator;
    }

    @Override
    public Captcha<SingleVerifiable<V>,SimpleImage> create() {
        codeCreator.create();
        Captcha<SingleVerifiable<V>,String> textCaptcha = codeCreator.create();
        String code = (String) textCaptcha.getDisplay();
        BufferedImage buffImg = drawCaptcha(code);

        return new Captcha<>(textCaptcha.getVerifiable(), new SimpleImage(buffImg));
    }

    /**
     * 使用默认纯文字验证码生成器构造一个图片验证码生成器
     * 
     * @return
     */
    public static SimpleImageCaptchaCreator<String> buildTextImageCaptchaCreator() {
        return new SimpleImageCaptchaCreator<String>(new TextCaptchaCreator());
    }

    /**
     * 使用数学公式生成器构造一个图片验证码生成器
     * 
     * @return
     */
    public static SimpleImageCaptchaCreator<Integer> buildMathImageCaptchaCreator() {
        return new SimpleImageCaptchaCreator<Integer>(new MathCaptchaCreator());
    }

    @Override
    public SingleVerifiable<V> parse(String verifiableString) {
        return codeCreator.parse(verifiableString);
    }

    /**
     * 绘制验证码
     * 
     * @param textCaptcha
     * @param captchaParam
     * @return
     */
    BufferedImage drawCaptcha(String captcha) {
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImg.createGraphics();
        // 绘制背景
        drawBackground(g);
        // 绘制随机码
        drawString(g, captcha);
        g.dispose();
        return buffImg;
    }

    /**
     * 画背景
     * 
     * @param g
     * @param width
     * @param height
     */
    protected void drawBackground(Graphics2D g) {
        g.setColor(CaptchaUtils.getRandColor(20, 180));
        g.fillRect(0, 0, width, height);
        // 画边框
        if (isDrawBorder) {
            g.setColor(g.getColor()
                    .darker());
            g.drawRect(0, 0, width - 1, height - 1);
        } else {
            g.drawRect(0, 0, width, height);
        }
        // 随机产生干扰线
        int start_x,start_y,end_x,end_y,i = 0;
        int rndNum = RandomUtils.nextInt(20, 50);
        // 虚线笔触
        if (RandomUtils.nextBoolean()) {
            float[] dashPattern = { 5.0f,3.0f }; // 虚线的长度和间隔
            BasicStroke dashedStroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f,
                    dashPattern, 0.0f);
            g.setStroke(dashedStroke);
        }
        for (i = 0; i < rndNum; i++) {
            g.setColor(CaptchaUtils.getRandColor(60, 180));
            start_x = RandomUtils.nextInt(0, width);
            start_y = RandomUtils.nextInt(0, height);
            end_x = RandomUtils.nextInt(1, width / 2);
            end_y = RandomUtils.nextInt(1, height / 2);
            if (i % 3 == 0) {
                g.drawOval(start_x, start_y, end_x, end_y);
            } else {
                g.drawLine(start_x, start_y, end_x, end_y);
            }
        }

    }

    /**
     * 画随机码
     * 
     * @param randomCode
     * @param g
     * @param width
     * @param height
     */
    protected void drawString(Graphics2D g, String captcha) {
        Font font;
        if (defaultFont == null) {
            int fh = (int) (height * 0.75f);
            int fstyle = CaptchaUtils.nextInt(4);
            font = new Font(Font.SANS_SERIF, fstyle, fh);
        } else {
            font = defaultFont;
        }

        g.setFont(font);
        Point p = ImageHelper.calcCenterPoint(g, width, height, captcha);
        int x = RandomUtils.nextInt(0, p.x);
        int gradientEndX = width / 2 - x;
        Color gradientEndColor = CaptchaUtils.getRandColor(60, 180);
        // 颜色渐变
        GradientPaint paint = new GradientPaint(x, 1, g.getBackground()
                .darker(), gradientEndX, p.y, gradientEndColor, true);
        g.setPaint(paint);

        if (RandomUtils.nextBoolean()) {
            // 倾斜效果
            g.shear(0.1, -0.2);
            p.y = height - 1;
        }

        g.drawString(captcha, x, p.y);
    }

    public void setDefaultFont(Font defaultFont) {
        this.defaultFont = defaultFont;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setDrawBorder(boolean drawBorder) {
        this.isDrawBorder = drawBorder;
    }

}
